package com.augmentum.springcloudorderservice.controller;

import com.augmentum.springcloudorderservice.common.ServerResult;
import com.augmentum.springcloudorderservice.domain.order.Order;
import com.augmentum.springcloudorderservice.domain.orderitem.OrderItem;
import com.augmentum.springcloudorderservice.domain.product.ProductInfo;
import com.augmentum.springcloudorderservice.dto.OrderDto;
import com.augmentum.springcloudorderservice.dto.ProductDto;
import com.augmentum.springcloudorderservice.feignclient.ProductClient;
import com.augmentum.springcloudorderservice.service.OrderItemService;
import com.augmentum.springcloudorderservice.service.OrderService;
import com.augmentum.springcloudorderservice.util.KeyUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/order")
@Slf4j
public class OrderController {
    @Resource
    private LoadBalancerClient loadBalancerClient;

    @Resource
    private RestTemplate restTemplate;

    @Resource
    private ProductClient productClient;

    @Resource
    private OrderItemService orderItemService;

    @Resource
    private OrderService orderService;

    @GetMapping("/msg")
    public String hello(String name) {
        RestTemplate restTemplate2 = new RestTemplate();
        String msg = null;

        // way one
        /*RestTemplate restTemplate = new RestTemplate();
        msg = restTemplate.getForObject("http://localhost:8080/product/msg", String.class, name); */

        // way two     application-name: application-name-product-service
        //             instance-name:    SPRING-CLOUD-APPNAME-PRODUCT-SERVICE
        /*ServiceInstance choose = loadBalancerClient.choose("PRODUCT-SERVICE-NAME");
        log.info("----------------------------------------------------------------");
        log.info(choose.toString());
        log.info("----------------------------------------------------------------");
        msg = restTemplate2.getForObject("http://" + choose.getHost() + ":" + choose.getPort() + "/product/msg", String.class, name);
        log.debug(msg);*/

        // way three
        Map<String, String> params = new HashMap<>();
        params.put("name", name);
        msg = restTemplate.getForObject("http://PRODUCT-SERVICE-NAME/product/msg", String.class, params);

        return msg;
    }

    @PostMapping
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public ServerResult<Map<String, String>> create(@RequestBody OrderDto orderDto) {
        List<String> productIds = orderDto.getItems().stream().map(ProductDto::getProductId).collect(Collectors.toList());

        List<ProductInfo> productInfos = productClient.findProductsByIds(productIds);


        /* 1. Decrease product stock. */
        productClient.decreaseStock(orderDto.getItems());

        /* 2. Count order's price */
        AtomicReference<BigDecimal> amount = new AtomicReference<>(new BigDecimal(BigInteger.ZERO));
        productInfos.forEach(productInfo -> {
            for (ProductDto productDto : orderDto.getItems()) {
                if (productInfo.getProductId().equalsIgnoreCase(productDto.getProductId())) {
                    amount.set(productInfo.getProductPrice()
                            .multiply(new BigDecimal(productDto.getProductQuantity()))
                            .add(amount.get()));
                    break;
                }
            }
        });

        /* 3. Insert a order */
        Order order = orderService.create(orderDto, amount.get());
        /* 4. Insert order items */
        List<OrderItem> orderItems = new ArrayList<>();
        orderDto.getItems().forEach(productDto -> {
            OrderItem orderItem = new OrderItem();


            for (ProductInfo productInfo : productInfos) {
                if (productInfo.getProductId().equalsIgnoreCase(productDto.getProductId())) {
                    BeanUtils.copyProperties(productInfo, orderItem);
                    break;
                }
            }

            orderItem.setOrderId(order.getOrderId());
            orderItem.setProductQuantity(productDto.getProductQuantity());
            orderItem.setProductId(orderItem.getProductId());
            orderItem.setDetailId(KeyUtil.generateOrderKey());
            orderItem.setCreateTime(null);
            orderItem.setUpdateTime(null);

            orderItems.add(orderItem);
        });

        orderItemService.create(orderItems);

        Map<String, String> data = new HashMap<>();
        data.put("orderId", order.getOrderId());
        return ServerResult.success(data);
    }
}
